home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / lh113src.zip / LHARC.C < prev    next >
Text File  |  1989-05-14  |  42KB  |  1,661 lines

  1. /*************************************************
  2.         LHarc version 1.13b (c)Yoshi, 1988-89.
  3.         main module : 1989/ 5/14
  4.  
  5. HTAB = 4
  6. *************************************************/
  7.  
  8. #include <stdio.h>
  9. #include <io.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12. #include <dir.h>
  13. #include <dos.h>
  14. #include <alloc.h>
  15. #include <fcntl.h>
  16. #include <process.h>
  17. #include <stdlib.h>
  18. #include <errno.h>
  19.  
  20. #define UNKNOWNERR    0
  21. #define INVCMDERR    1
  22. #define MANYPATERR    2
  23. #define NOARCNMERR    3
  24. #define NOFNERR        4
  25. #define NOARCERR    5
  26. #define RENAMEERR    6
  27. #define MKTMPERR    7
  28. #define DUPFNERR    8
  29. #define TOOMANYERR    9
  30. #define TOOLONGERR    10
  31. #define NOFILEERR    11
  32. #define MKFILEERR    12
  33. #define RDERR        13
  34. #define WTERR        14
  35. #define MEMOVRERR    15
  36. #define INVSWERR    16
  37. #define CTRLBRK        17
  38. #define NOMATCHERR    18
  39. #define COPYERR        19
  40. #define NOTLZH        20
  41. #define OVERWT        21
  42. #define MKDIR        22
  43. #define MKDIRERR    23
  44. #define CRCERR        24
  45. #define RDONLY        25
  46.  
  47. #define MAXBLK        64
  48.  
  49. #define MAX_PAT    64
  50. #define FAULT 0
  51. #define SUCCS ~FAULT
  52. #define getch() (bdos(0x08, 0, 0) & 0xff)
  53.  
  54. typedef unsigned char uchar;
  55. typedef unsigned int uint;
  56. typedef unsigned long ulong;
  57.  
  58. FILE  *file1, *file2, *file3, *infile, *outfile;
  59. int   cmd;                        /* command */
  60. int   cmdupdate;                /* Not zero, when updating archive */
  61. int   errorlevel = 0;            /* return value */
  62. long  textsize;                    /* file size before compression */
  63. long  codesize;                    /* file size after  compression */
  64. long  arcpos0;                    /* position pointer for archive */
  65. uchar *basedir;                    /* base directory (home-directory) */
  66. uchar *wdir = "";                /* work directory */
  67. uchar workdir[MAXPATH];            /* work directory */
  68. uchar *infname;                    /* input  file name (for error message) */
  69. uchar *outfname;                /* output file name (for error message)*/
  70. int   attr;                        /* file attributes for search files */
  71. int   Nfile;                    /* number of files which was found */
  72. int   fblft, fbsize;            /* for buffers handling file names */
  73. uint  seg;                        /* beginning segment of file name buffers */
  74. uchar far *fbuf, huge *fbnxt;    /* pointer to file name buffers */
  75. uchar arcname[MAXPATH];            /* archive name */
  76. uchar pathname[MAXPATH];        /* work for file name (extracting) */
  77. uchar filename[MAXPATH];        /* work for file name (for file in archive) */
  78. int   patno;                    /* No. of path names in command line */
  79. uchar patfile[MAX_PAT][12];        /* file name in command line */
  80. uchar *patpath[MAX_PAT];        /* directory name in command line */
  81. int   patcnt[MAX_PAT];            /* counts which this name matched */
  82. uchar patnul[] = "*.*";            /* default path name */
  83. uchar backup1[MAXPATH], backup2[MAXPATH];
  84.                                 /* temporary file names */
  85. uchar flg_r = 0, flg_p = 0, flg_x = 0, flg_m = 0;
  86. uchar flg_a = 0, flg_c = 0, flg_v = 0, flg_w = 0;
  87. uchar flg_n = 0, flg_t = 0;
  88.                                 /* switches */
  89. uchar copying = 0;                /* turn on when copying temporary file */
  90. uchar crcflg = 0;                /* force copyfile() to calculate CRC*/
  91. uchar tstflg = 0;                /* turn on in 't' command */
  92. uchar swchar;                    /* switch character */
  93. uchar *pager = "less";            /* utility used in 'p /v' mode */
  94. uint  crc;                        /* calculated CRC code */
  95. uchar *keyword = "";            /* key word for auto-execution */
  96.  
  97. struct filebuf {                /* work for file name buffer */
  98.     void far *next;
  99.     uchar fpos;                    /* position of file name */
  100.     uchar cpos;                    /* position of effective path name */
  101.     uchar dir[MAXDIR];            /* full path name */
  102. } fb0, fb1;
  103.  
  104. extern char  *errmes[];            /* array of pointers to error messages */
  105. extern uchar  use[];            /* usage */
  106. extern uchar buf2[], buf3[];    /* I/O buffers */
  107.  
  108. /* routines for handling Japanese strings */
  109. extern uchar *j_strupr(uchar *p);
  110. extern int    j_strcmp(char *p, char *q);
  111. extern uchar *j_strchr(char *p, uint c);
  112. extern uchar *j_strrchr(char *p, uint c);
  113.  
  114. extern int    getfattr(uchar *fn);            /* get file attributes */
  115. extern void   setfattr(uchar *fn, int attr);/* set file attributes */
  116. extern uchar  getswchar(void);                /* get switch character */
  117. extern void   slash2yen(uchar *p);            /* convert '/' to '\' */
  118.  
  119. extern char M_NOMATCHERR[];
  120. extern char M_COPYERR[];
  121. extern char M_NOTLZH[];
  122. extern char M_OVERWT[];
  123. extern char M_MKDIR[];
  124. extern char M_MKDIRERR[];
  125. extern char M_CRCERR[];
  126. extern char M_RDONLY[];
  127.  
  128. union stamp {                    /* time stamp */
  129.     struct ftime s;
  130.     ulong u;
  131. };
  132.  
  133. union stamp arcstamp = {0L};    /* time stamp for archive */
  134.  
  135. struct LzHead {                    /* file header */
  136.     uchar HeadSiz, HeadChk, HeadID[5];
  137.     ulong PacSiz, OrgSiz;
  138.     union stamp Ftime;
  139.     uint  Attr;
  140.     uchar Fname[MAXPATH];
  141. } Hdr1, Hdr2;
  142.  
  143. struct exeHead {                /* EXE header for SFX */
  144.     uint exeID, byte, page, reloc;
  145.     uint hdrsize, minalloc, maxalloc, initSS;
  146.     uint initSP, chksum, initIP, initCS;
  147.     uint reloctab, overlay, dummy1, dummy2;
  148. } ExeHdr = {
  149.     'MZ', 0, 0, 0, 2, 0, 0xffff, 0xfff0,
  150.     0x100, 0, 0x100, 0xfff0, 0x1e, 0, 0, 0
  151. };
  152.  
  153. /*******************************
  154.         display helps
  155. *******************************/
  156. void usage(void)
  157. {
  158.     fputs(use, stdout);
  159.     exit(0);
  160. }
  161.  
  162. /*******************************
  163.         display a message
  164. *******************************/
  165.  
  166. void message(uchar *p, uchar *q)
  167. {
  168.     printf("%s", p);
  169.     if (q) {
  170.         printf(" : '%s'", q);
  171.     }
  172.     printf("\n");
  173. }
  174.  
  175. /*******************************
  176.     process for an error
  177. *******************************/
  178. void error(int errcode, uchar *p)
  179. {
  180.     if (copying) {                        /* error during copying temporary? */
  181.         fprintf(stderr, "\n%s\n", M_COPYERR);
  182.         fclose(file1);
  183.         unlink(arcname);                /* erase incomplete archive */
  184.         file1 = NULL;
  185.     }
  186.     fprintf(stderr, "\n%s", errmes[errcode]);
  187.     if (p) {
  188.         fprintf(stderr, " : '%s'", p);
  189.     }
  190.     fprintf(stderr, "\n");
  191.     if (file3) {
  192.         fclose(file3);
  193.         if (!cmdupdate)                    /* during extracting */
  194.             unlink(pathname);           /* delete the file */
  195.     }
  196.     if (file1) {
  197.         fclose(file1);
  198.         if (cmdupdate)                    /* during updating */
  199.             rename(backup1, arcname);    /* recover old archive */
  200.     }
  201.     if (file2) {
  202.         fclose(file2);
  203.         if (!copying) {                    /* if not copying */
  204.             unlink(backup2);            /* delete temporary */
  205.         }
  206.     }
  207.     if (copying)
  208.         exit(3);
  209.     else
  210.         exit(2);
  211. }
  212.  
  213. /*******************************
  214.         handle user break
  215. *******************************/
  216. int userbreak(void)
  217. {
  218.     error(CTRLBRK, NULL);
  219. }
  220.  
  221. /*******************************
  222.     fopen with detecting error
  223. *******************************/
  224. FILE *e_fopen(uchar *fname, uchar *mode, int errID)
  225. {
  226.     FILE *f;
  227.  
  228.     if ((f = fopen(fname, mode)) == NULL) {
  229.         if (errno == EACCES)
  230.             error(RDONLY, fname);
  231.         error(errID, fname);
  232.     }
  233.     return f;
  234. }
  235.  
  236. /*******************************
  237.     rename with detecting error
  238. *******************************/
  239. void e_rename(uchar *old, uchar *new)
  240. {
  241.     if (rename(old, new))
  242.         error(RENAMEERR, old);
  243. }
  244.  
  245. /*******************************
  246.         ask 'Y' or 'N'
  247. *******************************/
  248. uint getyn(void)
  249. {
  250.     uint yn;
  251.  
  252.     do {
  253.         yn = toupper(getch());
  254.     } while (yn != 'Y' && yn != 'N');
  255.     fprintf(stderr, "%c\n", yn);
  256.     return yn;
  257. }
  258.  
  259. /*******************************
  260.   file name -> internal format
  261. *******************************/
  262. void extfn(uchar *p, uchar *pb)
  263. {
  264.     int i;
  265.     uchar * q;
  266.  
  267.     if ((q = j_strrchr(p, '\\')) != NULL ||
  268.         (q = j_strchr(p, ':')) != NULL)
  269.         p = q + 1;
  270.     q = p;
  271.     for (i = 8; i > 0; i--, pb++) {
  272.         switch (*p) {
  273.         case '*':
  274.             *pb = '?';
  275.             break;
  276.         case '.':
  277.         case '\0':
  278.             *pb = ' ';
  279.             break;
  280.         default:
  281.             *pb = *p++;
  282.         }
  283.     }
  284.     while (+(*p != '\0' && *p++ != '.'));
  285.     for (i = 3; i > 0; i--, pb++) {
  286.         switch (*p) {
  287.         case '*':
  288.             *pb = '?';
  289.             break;
  290.         case '\0':
  291.             *pb = ' ';
  292.             break;
  293.         default:
  294.             *pb = *p++;
  295.         }
  296.     }
  297.     *q = *pb = '\0';
  298. }
  299.  
  300. /*******************************
  301.   internal format -> file name
  302. *******************************/
  303. void packfn(uchar *p, uchar *q)
  304. {
  305.     int i;
  306.  
  307.     for (i = 8; i > 0; i--) {
  308.         if (*q != ' ')
  309.             *p++ = *q;
  310.         q++;
  311.     }
  312.     *p++ = '.';
  313.     for (i = 3; i > 0; i--) {
  314.         if (*q != ' ')
  315.             *p++ = *q;
  316.         q++;
  317.     }
  318.     if (p[-1] == '.')
  319.         p--;
  320.     *p = '\0';
  321. }
  322.  
  323. /*******************************
  324.   get back to parent directory
  325. *******************************/
  326. uchar *backpath(uchar *p)
  327. {
  328.     uchar *q;
  329.  
  330.     if ((q = j_strrchr(p, '\\')) == NULL &&
  331.         (q = j_strchr(p, ':')) == NULL) {
  332.         *p = '\0';
  333.         q = p;
  334.     } else {
  335.         *++q = '\0';
  336.     }
  337.     return q;
  338. }
  339.  
  340. /***********************************
  341.   whether path name was used or not
  342. ***********************************/
  343. void tstpat(void)
  344. {
  345.     int i, cnt;
  346.     uchar path[MAXPATH];
  347.  
  348.     cnt = 0;
  349.     for (i = 0; i < patno; i++)
  350.         cnt += patcnt[i];
  351.     if (cnt == 0)                        /* no file matched */
  352.         error(NOFILEERR, NULL);
  353.     for (i = 0; i < patno; i++) {
  354.         if (patcnt[i] == 0) {            /* if any path name was not used */
  355.             packfn(stpcpy(path, patpath[i]), patfile[i]);
  356.             fprintf(stderr, "%s : '%s'\n", M_NOMATCHERR, path);
  357.             errorlevel = 1;                /* display warning */
  358.         }
  359.     }
  360. }
  361.  
  362. /*******************************
  363.         make a file header
  364. *******************************/
  365. void sethdr(uchar *fn, uint attr, struct LzHead *h)
  366. {
  367.     uint l;
  368.  
  369.     memset(h, 0, sizeof(struct LzHead));
  370.     l = strlen(fn);                        /* length of file name */
  371.     h -> Fname[0] = l;
  372.     memcpy(h -> Fname + 1, fn, l);
  373.     l += 20 + 2;                        /* size of header */
  374.     h -> HeadSiz = l;
  375.     fseek(file3, 0L, SEEK_END);
  376.     h -> OrgSiz = textsize = ftell(file3);    /* original size of a file */
  377.     h -> PacSiz = codesize = 0;
  378.     rewind(file3);
  379.     getftime(fileno(file3), &(h -> Ftime.s));    /* get time stamp */
  380.     h -> Attr = attr;                    /* file attributes */
  381.     memcpy(h -> HeadID, "-lh1-", 5);    /* at first, select the method -lh1- */
  382. }
  383.  
  384. /*******************************
  385.     write a file header
  386. *******************************/
  387. void wthdr(struct LzHead *h)
  388. {
  389.     arcpos0 = ftell(file2);        /* memorize this position */
  390.     if (fwrite(h, h -> HeadSiz + 2, 1, file2) == 0)
  391.         error(WTERR, backup2);
  392. }
  393.  
  394. /*******************************
  395.   calculate check-sum of header
  396. *******************************/
  397. uchar mksum(struct LzHead *h)
  398. {
  399.     uchar *p, *q;
  400.     uchar i;
  401.  
  402.     p = (uchar *)h + 2;
  403.     q = p + h -> HeadSiz;
  404.     for (i = 0; p < q; p++)
  405.         i += *p;
  406.     return i;
  407. }
  408.  
  409. /*******************************
  410.     remake file header & write
  411. *******************************/
  412. void remkhdr(struct LzHead *h)
  413. {
  414.     int flg;
  415.     long arcpos1;
  416.  
  417.     flg = 0;
  418.     h -> PacSiz = codesize;                /* packed size of a file */
  419.     *(uint *)(h -> Fname + *(h -> Fname) + 1) = crc;
  420.     if (h -> OrgSiz <= codesize) {        /* if packed size >= original size */
  421.         flg = 1;                        /* select method "simple copy" */
  422.         memcpy(h -> HeadID, "-lh0-", 5);
  423.         h -> PacSiz = h -> OrgSiz;
  424.     }
  425.     h -> HeadChk = mksum(h);            /* header sum */
  426.     arcpos1 = ftell(file2);                /* memorize this position */
  427.     fseek(file2, arcpos0, SEEK_SET);    /* seek to header */
  428.     fwrite(h, h -> HeadSiz + 2, 1, file2); /* rewrite header */
  429.     if (flg) {
  430.         rewind(file3);
  431.         copyfile(file3, file2, h -> OrgSiz);    /* do simple copy */
  432.     } else {
  433.         fseek(file2, arcpos1, SEEK_SET);        /* return to the end */
  434.     }
  435. }
  436.  
  437. /*******************************
  438.         get a file header
  439. *******************************/
  440. uchar *gethdr(FILE *arc, struct LzHead *h)
  441. {
  442.     uchar *q, i;
  443.  
  444.     if ((h -> HeadSiz = getc(arc)) <= 0 ||
  445.         h -> HeadSiz > sizeof(struct LzHead) - 3 ||
  446.         fread(&(h -> HeadChk), h -> HeadSiz + 1, 1, arc) == 0)
  447.     {                                /* read file header */
  448.         return NULL;
  449.     }
  450.     if (mksum(h) != h -> HeadChk)    /* if sum is wrong */
  451.         return NULL;
  452.     i = *(h -> Fname);
  453.     strncpy(filename, h -> Fname + 1, i);
  454.     *(filename + i) = '\0';
  455.     if ((q = j_strrchr(filename, '\\')) == NULL &&
  456.         (q = j_strchr(filename, ':')) == NULL)
  457.         q = filename;
  458.     else
  459.         q++;
  460.     return q;                    /* return the portion of file name */
  461. }
  462.  
  463. /*******************************
  464.     test match of file name
  465. *******************************/
  466. int matchpat(uchar *p)
  467. {
  468.     uchar buf[12], name[MAXPATH];
  469.     int i, j, retcode;
  470.  
  471.     retcode = FAULT;
  472.     strcpy(name, p);
  473.     extfn(name, buf);
  474.     for (i = 0; i < patno; i++) {
  475.         if (flg_p || *patpath[i]) {        /* should compare full path ? */
  476.             if (j_strcmp(name, patpath[i]))
  477.                 continue;
  478.         }
  479.         for (j = 0; j < 11; j++) {        /* compare file name */
  480.             if (patfile[i][j] != buf[j] && patfile[i][j] != '?')
  481.             break;
  482.         }
  483.         if (j == 11) {                    /* if matched */
  484.             patcnt[i]++;
  485.             retcode = SUCCS;
  486.         }
  487.     }
  488.     return retcode;
  489. }
  490.  
  491. /*******************************
  492.         ratio * 1000
  493. *******************************/
  494. uint ratio(ulong a, ulong b)
  495. {
  496.     int i;
  497.  
  498.     if (!b) return 0;            /* if diviser == 0 */
  499.     for (i = 0; i < 3 && a < 0x19999999; i++) {
  500.         a *= 10;                /* while not overflow */
  501.     }                            /* upto 1000 times */
  502.     for (; i < 3; i++) {        /* the case of overflow */
  503.         b /= 10;
  504.     }
  505.     a += b / 2;                    /* for round up */
  506.     return (a / b);                /* return (a * 1000 / b) */
  507. }
  508.  
  509. /*******************************
  510.         compare names
  511. *******************************/
  512. int cmpname(uchar *f0, uchar *f1, uchar *p0, uchar *p1)
  513. {
  514.     int c;
  515.  
  516.     c = j_strcmp(f0, f1);                /* compare only file names */
  517.     if (c == 0) {
  518.         c = strlen(p0) - strlen(p1);    /* compare lengths of path names */
  519.         if (c == 0) {
  520.             c = j_strcmp(p0, p1);        /* compare path names */
  521.         }
  522.     }
  523.     return c;
  524. }
  525.  
  526. /*******************************
  527.     regist file names
  528. *******************************/
  529. void regfile(uchar *p, uchar *q, uchar *f)
  530. /*
  531.     p: full path name including base directory
  532.     q: directory name to be registed
  533.     f: file name
  534. */
  535. {
  536.     uchar path[MAXPATH];
  537.     struct filebuf far *f0;
  538.     struct filebuf far *f1;
  539.     uchar *s;
  540.     int c, size;
  541.  
  542.     if (strstr(f, "LHARC.)1(") || strstr(f, "LHARC.)2("))
  543.         return;                    /* temporary file ? */
  544.     stpcpy(stpcpy(path, q), f);
  545.     stpcpy(s = stpcpy(fb1.dir, p), f);
  546.     fb1.fpos = s - (uchar *)&fb1;
  547.     fb1.cpos = flg_x ? (q - p) + (fb1.dir - (uchar *)&fb1) : fb1.fpos;
  548.     if (fbuf == NULL) {                /* for first entry */
  549.         if (allocmem(fbsize = 0x100, &seg) != -1)
  550.             error(MEMOVRERR, NULL);
  551.         fbuf = (uchar far *)fbnxt = MK_FP(seg, 0);
  552.         fblft = 0x1000 - 4;
  553.         *(long far *)fbuf = 0;
  554.         fbnxt += 4;
  555.     }
  556.     f0 = (struct filebuf far *)fbuf;
  557.     do {                    /* search position in which should be inserted*/
  558.         f1 = f0;
  559.         if ((f0 = f0 -> next) == NULL)
  560.             break;
  561.         fb0 = *f0;
  562.         c = cmpname((uchar *)&fb0 + fb0.fpos, (uchar *)&fb1 + fb1.fpos,
  563.                     (uchar *)&fb0 + fb0.cpos, (uchar *)&fb1 + fb1.cpos);
  564.     } while (c < 0);
  565.  
  566.     if (f0 && c == 0 && j_strcmp(fb0.dir, fb1.dir)) {
  567.         error(DUPFNERR, (uchar *)&fb1 + fb1.cpos);
  568.     }                        /* same registing names of different files */
  569.  
  570.     if (f0 == NULL || c) {                /* do regist */
  571.         size = strlen(fb1.dir) +
  572.               (fb1.dir - (uchar *)&fb1) + 1;
  573.         if (fblft < sizeof(struct filebuf)) {    /* if buffer is short */
  574.             if (setblock(seg, fbsize += 0x100) != -1)
  575.                 error(TOOMANYERR, NULL);
  576.             fblft += 0x1000;
  577.         }
  578.         fb1.next = f0;
  579.         f0 = (struct filebuf far *)fbnxt;
  580.         f1 -> next = f0;
  581.         *f0 = fb1;
  582.         fblft -= size;
  583.         fbnxt += size;
  584.     }
  585. }
  586.  
  587. /*******************************
  588.   recursive collection of files
  589. *******************************/
  590. int travel(uchar *p, uchar *q, uchar *f)
  591. {
  592.     struct ffblk ffb;
  593.     static uchar buf[12];
  594.     uchar *r, *s;
  595.     int done, cnt, j;
  596.  
  597.     cnt = 0;
  598.     if (flg_r == 1 || j_strrchr(q, '\\') == q + strlen(q) - 1) {
  599.         stpcpy(s = q + strlen(q), "*.*");
  600.     }
  601.     done = findfirst(p, &ffb, attr);    /* search the first file */
  602.     s = backpath(q);
  603.     while (! done) {
  604.         if (ffb.ff_attrib & 0x10) {        /* if this is a sub-directory */
  605.             if (ffb.ff_name[0] != '.') {
  606.                 r = stpcpy(stpcpy(s, ffb.ff_name), "\\");
  607.                 if (r - p > MAXPATH)
  608.                     error(TOOLONGERR, p);
  609.                 cnt += travel(p, q, f);    /* search recursively */
  610.                 *s = '\0';
  611.             }
  612.         } else                            /* if this is a file */
  613.         if (flg_r == 2) {                /* in /r2 mode */
  614.             cnt++;
  615.             regfile(p, q, ffb.ff_name);            /* regist name */
  616.         } else {                        /* in /r+ mode */
  617.             stpcpy(s, ffb.ff_name);
  618.             extfn(s, buf);
  619.             for (j = 0; j < 11; j++) {            /* test file names */
  620.                 if (f[j] != buf[j] && f[j] != '?')
  621.                 break;
  622.             }
  623.             if (j == 11) {
  624.                 cnt++;
  625.                 regfile(p, q, ffb.ff_name);        /* if match, regist */
  626.             }
  627.         }
  628.         done = findnext(&ffb);
  629.     }
  630.     return cnt;                            /* number of registed files */
  631. }
  632.  
  633. /**********************************
  634.  non-recursive collection of files
  635. **********************************/
  636. int findfile(uchar *p, uchar *q)
  637. {
  638.     struct ffblk ffb;
  639.     int done, cnt;
  640.  
  641.     cnt = 0;
  642.     done = findfirst(p, &ffb, attr);
  643.     backpath(p);
  644.     while (! done) {
  645.         cnt++;
  646.         regfile(p, q, ffb.ff_name);
  647.         done = findnext(&ffb);
  648.     }
  649.     return cnt;
  650. }
  651.  
  652. /*******************************
  653.     make file lists to append
  654. *******************************/
  655. void mklist(void)
  656. {
  657.     uchar path[MAXPATH], *p, *q, *r;
  658.     int i, cnt;
  659.  
  660.     Nfile = 0;
  661.     if (flg_a) {                        /* set attributes for search */
  662.         attr = 0x07;
  663.     } else {
  664.         attr = 0;
  665.     }
  666.     if (flg_r) {
  667.         attr |= 0x10;
  668.     }
  669.     for (i = 0; i < patno; i++) {
  670.         p = patpath[i];
  671.         q = path;
  672.         if (*p && p[1] == ':') {        /* if path name includes drive */
  673.             q = stpcpy(path, p);            /* ignore base directory */
  674.             r = path + 2;                    /* don't regist drive name */
  675.         } else {
  676.             q = stpcpy(r = stpcpy(path, basedir), p);
  677.         }
  678.         if (flg_r == 1) {                /* /r+ mode */
  679.             cnt = travel(path, r, patfile[i]);
  680.         } else if (flg_r > 1) {            /* /r2 mode */
  681.             packfn(q, patfile[i]);
  682.             cnt = travel(path, r, NULL);
  683.         } else {                        /* /r- mode */
  684.             packfn(q, patfile[i]);
  685.             cnt = findfile(path, r);
  686.         }
  687.         Nfile += patcnt[i] = cnt;
  688.     }
  689. }
  690.  
  691. /*******************************
  692.         make file header
  693. *******************************/
  694. uchar *mkhdr(struct filebuf far *f, struct LzHead *h)
  695. {
  696.     int attr;
  697.  
  698.     fb0 = *f;
  699.     attr = getfattr(fb0.dir);
  700.     file3 = e_fopen(fb0.dir, "rb", RDERR);
  701.     sethdr((uchar *)&fb0 + fb0.cpos, attr, h);
  702.     return (uchar *)&fb0 + fb0.fpos;    /* position of file name */
  703. }
  704.  
  705. uint blkcnt;
  706. uint curcnt;
  707. uint nxtcnt;
  708. uint namcnt;
  709.  
  710. /*******************************
  711.     calculate and display
  712.         for indicator
  713. *******************************/
  714. void blkdisp(long l, char *s) {
  715.     uint i;
  716.  
  717.     if (flg_n == 0) {
  718.         fprintf(stderr, "\n  %s :  ", s);
  719.         blkcnt = (l + 4095) / 4096;
  720.         i = (blkcnt > MAXBLK) ? MAXBLK : blkcnt;
  721.         while (i-- > 0) {
  722.             putc('.', stderr);
  723.         }
  724.         fprintf(stderr, "\r  %s :  ", s);
  725.         curcnt = nxtcnt = 0;
  726.     } else {
  727.         curcnt = 0;
  728.         nxtcnt = -1;
  729.     }
  730. }
  731.  
  732. /*******************************
  733.     let cursor back after
  734.     displaying indicator
  735. *******************************/
  736. void curback(void)
  737. {
  738.     if (flg_n == 0) {
  739.         fprintf(stderr, "\r  ");
  740.     }
  741. }
  742.  
  743. /*******************************
  744.         freeze a file
  745. *******************************/
  746. void freeze(uchar *p)
  747. {
  748.     if (arcstamp.u < Hdr2.Ftime.u)
  749.         arcstamp.u = Hdr2.Ftime.u;
  750.     printf("%s ", p);
  751.     blkdisp(Hdr2.OrgSiz, "Freezing ");
  752.     wthdr(&Hdr2);
  753.     setvbuf(file3, buf3, _IOFBF, 4096);
  754.     infile = file3;
  755.     outfile = file2;
  756.     infname = p;
  757.     crc = 0;
  758.     Encode();
  759.     remkhdr(&Hdr2);
  760.     curback();
  761.     printf("Frozen(%3d%%)\n", ratio(Hdr2.PacSiz, Hdr2.OrgSiz) / 10);
  762. }
  763.  
  764. /*******************************
  765.         Copy a file from
  766.             old archive
  767. *******************************/
  768. void copyold()
  769. {
  770.     if (arcstamp.u < Hdr1.Ftime.u)
  771.         arcstamp.u = Hdr1.Ftime.u;
  772.     wthdr(&Hdr1);                /* copy from old archive */
  773.     copyfile(file1, file2, Hdr1.PacSiz);
  774. }
  775.  
  776. /*******************************
  777.       execute one of a, u, m
  778.         commands
  779. *******************************/
  780. int execappend(void)
  781. {
  782.     struct filebuf far *f0;
  783.     uchar *p, *q;
  784.     int c, d;
  785.     int cnt = 0;
  786.  
  787.     q = file1 ? gethdr(file1, &Hdr1) : NULL;    /* read header from old arc */
  788.     if ((f0 = ((struct filebuf far *)fbuf) -> next) != NULL) {
  789.         p = mkhdr(f0, &Hdr2);            /* make header from the file list */
  790.     }
  791.     while (1) {
  792.         if (f0 == NULL) {
  793.             d = 1;
  794.             if (q == NULL)
  795.                 break;
  796.         } else if (q == NULL) {
  797.             d = -1;
  798.         } else {
  799.             d = cmpname(p, q, (uchar *)&fb0 + fb0.cpos, filename);
  800.         }
  801.         c = d;
  802.         if (c == 0) {
  803.             if (flg_c || Hdr1.Ftime.u < Hdr2.Ftime.u) {
  804.                 c = -1;
  805.             } else {
  806.                 c = 1;
  807.             }
  808.         }
  809.         if (c < 0) {                    /* freeze a new file */
  810.             if (d == 0) {
  811.                 fseek(file1, Hdr1.PacSiz, SEEK_CUR);
  812.                 q = gethdr(file1, &Hdr1);        /* skip a file in old */
  813.             }                                    /* archive */
  814.             freeze(fb0.dir);
  815.             fclose(file3);
  816.             cnt++;
  817.             if ((f0 = fb0.next) != NULL) {        /* make header of the next */
  818.                 p = mkhdr(f0, &Hdr2);            /* file in file list */
  819.             }
  820.         } else {                        /* copy a file from old archive */
  821.             if (d == 0) {
  822.                 fclose(file3);
  823.                 if ((f0 = fb0.next) != NULL) {    /* make header of the next */
  824.                     p = mkhdr(f0, &Hdr2);        /* file in file list */
  825.                 }
  826.             }
  827.             copyold();
  828.             q = gethdr(file1, &Hdr1);            /* get the next header */
  829.         }                                        /* in old archive */
  830.     }
  831.     return cnt;
  832. }
  833.  
  834. /*******************************
  835.     delete files after
  836.     execution of updating
  837.     in 'm' command
  838. *******************************/
  839. void delfile(void)
  840. {
  841.     struct filebuf far *f0;
  842.     struct filebuf fb0;
  843.  
  844.     f0 = (struct filebuf far *)fbuf;
  845.     while ((f0 = f0 -> next) != NULL) {
  846.         fb0 = *f0;
  847.         unlink(fb0.dir);
  848.     };
  849. }
  850.  
  851. /*******************************
  852.     open an old archive
  853. *******************************/
  854. void openarc1(void)
  855. {
  856.     uchar *p, *q;
  857.  
  858.     file1 = e_fopen(infname = arcname, "rb", NOARCERR);
  859.     q = buf2 - 5 + fread(buf2, 1, 2048, file1);
  860.     for (p = buf2; p < q; p++) {
  861.         if (p[0] == '-' && p[1] == 'l' && p[4] == '-') break;
  862.     }
  863.     if (p >= q) {
  864.         error(NOFILEERR, arcname);
  865.     }
  866.     fseek(file1, (long)(p - buf2 - 2), SEEK_SET);
  867. }
  868.  
  869. /*******************************
  870.     open an archive in rd/wt
  871.     for testing read-only
  872. *******************************/
  873. void openrwarc1(void)
  874. {
  875.     file1 = e_fopen(arcname, "r+b", NOARCERR);
  876. }
  877.  
  878. /*******************************
  879.     close an old archive
  880.     & rename to temporary
  881. *******************************/
  882. void openbackup1(void)
  883. {
  884.     fclose(file1);
  885.     stpcpy(backpath(strcpy(backup1, arcname)), "lharc.)1(");
  886.     e_rename(arcname, backup1);
  887.     file1 = fopen(infname = backup1, "rb");
  888. }
  889.  
  890. /*******************************
  891.     open a temporary file
  892.     for a new archive
  893. *******************************/
  894. void openbackup2(void)
  895. {
  896.     if (flg_w) {
  897.         stpcpy(stpcpy(backup2, workdir), "lharc.)2(");
  898.     } else {
  899.         strcat(backpath(strcpy(backup2, arcname)), "lharc.)2(");
  900.     }
  901.     file2 = e_fopen(outfname = backup2, "w+b", MKTMPERR);
  902.     setvbuf(file2, buf2, _IOFBF, 4096);
  903. }
  904.  
  905. /*******************************
  906.    set time & close an archive
  907. *******************************/
  908. void stclosearc(FILE *f)
  909. {
  910.     if (flg_t) {
  911.         fflush(f);
  912.         setftime(fileno(f), &arcstamp.s);
  913.     }
  914.     fclose(f);
  915. }
  916.  
  917. /*******************************
  918.     end-of-job process
  919.     in making new archive
  920. *******************************/
  921. void endofupdate(int cnt)
  922. {
  923.     stclosearc(file1);
  924.     tstpat();
  925.     if (cnt) {                    /* if any files are manipulated */
  926.         if (file1)
  927.             if (unlink(backup1))        /* delete an old archive */
  928.                 printf("debug : Failed in deleting '%s'.", backup1);
  929.         if ((arcpos0 = ftell(file2)) != 0) {
  930.             if (putc(0, file2) == EOF)
  931.                 error(WTERR, backup2);
  932.             if (flg_w) {            /* if work directory is assigned */
  933.                 rewind(file2);
  934.                 infname = backup2;
  935.                 copying = 1;            /* copy temporary to new archive */
  936.                 file1 = e_fopen(outfname = arcname, "wb", MKFILEERR);
  937.                 printf("Copying Temp to Archive ...");
  938.                 copyfile(file2, file1, arcpos0 + 1);
  939.                 printf("\n");
  940.                 copying = 0;
  941.                 stclosearc(file1);
  942.                 fclose(file2);
  943.                 unlink(backup2);
  944.             } else {
  945.                 stclosearc(file2);    /* else rename temporary to archive */
  946.                 rename(backup2, arcname);
  947.             }
  948.         } else {
  949.             fclose(file2);
  950.             unlink(backup2);
  951.         }
  952.     } else {                    /* if no change was made in archive */
  953.         fclose(file2);
  954.         unlink(backup2);
  955.         rename(backup1, arcname);    /* restore the old archive */
  956.     }
  957. }
  958.  
  959. /*******************************
  960.         a, u, m command
  961. *******************************/
  962. void append(void)
  963. {
  964.     int cnt;
  965.  
  966.     file1 = fopen(arcname, "r+b");
  967.     if (file1) {
  968.         openbackup1();                /* if archive presents, rename to temp */
  969.     } else {
  970.         if (errno == EACCES)
  971.             error(RDONLY, arcname);    /* read-only error */
  972.     }
  973.     mklist();                        /* make a file list */
  974.     if (Nfile == 0) {
  975.         error(NOFILEERR, NULL);
  976.     }
  977.     if (file1) {
  978.         message("Updating archive", arcname);
  979.     } else {
  980.         message("Creating archive", arcname);
  981.     }
  982.     openbackup2();                    /* open temporary for new archive */
  983.     cnt = execappend();                /* execute updating archive */
  984.     endofupdate(cnt);                /* end-of-job process */
  985.     if (cmd == 'M')
  986.         delfile();                    /* if 'm' command, delete files */
  987.     freemem(seg);
  988. }
  989.  
  990. /*******************************
  991.         f command
  992. *******************************/
  993. void freshen(void)
  994. {
  995.     uchar path[MAXPATH];
  996.     int c;
  997.     int    cnt = 0;
  998.  
  999.     openrwarc1();                        /* open an archive */
  1000.     message("Freshening archive", arcname);
  1001.     openbackup1();                        /* rename the archive to temp. */
  1002.     openbackup2();                        /* open temp. for a new archive */
  1003.     while (gethdr(file1, &Hdr1)) {
  1004.         c = 0;
  1005.         if (matchpat(filename)) {
  1006.             stpcpy(stpcpy(path, basedir), filename);
  1007.             if ((file3 = fopen(path, "rb")) != NULL) {
  1008.                 sethdr(filename, getfattr(path), &Hdr2);
  1009.                 if (flg_c || Hdr1.Ftime.u < Hdr2.Ftime.u) {
  1010.                     c = 1;              /* found the file to be updated */
  1011.                 }
  1012.             }
  1013.         }
  1014.         if (c) {
  1015.             freeze(path);                /* do updating */
  1016.             cnt++;
  1017.             fseek(file1, Hdr1.PacSiz, SEEK_CUR);
  1018.         } else {
  1019.             copyold();
  1020.         }
  1021.         fclose(file3);
  1022.     }
  1023.     endofupdate(cnt);                    /* end-of-job process */
  1024. }
  1025.  
  1026. /*******************************
  1027.     test the file which
  1028.     should be melted
  1029. *******************************/
  1030. int tstdir(uchar *name)
  1031. {
  1032.     uchar path[MAXPATH], *p, yn;
  1033.     struct ffblk ffb;
  1034.  
  1035.     p = name;
  1036.     if (*p && p[1] == ':')                /* skip a drive name */
  1037.         p += 2;
  1038.     if (*p == '\\')                        /* skip a root mark('\') */
  1039.         p++;
  1040.     yn = flg_m ? 'Y' : 'N';
  1041.     while ((p = j_strchr(p, '\\')) != NULL) {    /* skip to next '\' */
  1042.         memcpy(path, name, p - name);
  1043.         path[p - name] = '\0';
  1044.         if (findfirst(path, &ffb, 0x1f)) {    /* Is there this directory? */
  1045.             if (yn == 'N') {
  1046.                 fprintf(stderr, "'%s' : %s", name, M_MKDIR);
  1047.                 yn = getyn();
  1048.             }
  1049.             if (yn == 'N') {
  1050.                 return FAULT;
  1051.             } else {
  1052.                 if (mkdir(path)) {            /* make directory */
  1053.                     error(MKDIRERR, path);
  1054.                 }
  1055.             }
  1056.         } else {
  1057.             if ((ffb.ff_attrib & 0x10) == 0) {
  1058.                 error(MKDIRERR, path);    /* if the name isn't directory */
  1059.             }
  1060.         }
  1061.         p++;
  1062.     }
  1063.     if (! findfirst(name, &ffb, 0x1f)) {    /* if a file has the same name */
  1064.         if (ffb.ff_attrib & 0x01 && ffb.ff_attrib != Hdr1.Attr) {
  1065.                                 /* if the file is read-only, */
  1066.                                 /* attributes must match */
  1067.             fprintf(stderr, "'%s' %s\n", M_RDONLY);
  1068.             return FAULT;
  1069.         }
  1070.         yn = 'Y';
  1071.         if (flg_c == 0) {
  1072.             if (((ulong)ffb.ff_fdate << 16) + (ulong)ffb.ff_ftime
  1073.                     < Hdr1.Ftime.u) {    /* compare time stamps */
  1074.                 yn = 'Y';
  1075.             } else {
  1076.                 printf("Skipped : '%s' : New or same file exists.\n", name);
  1077.                 yn = 'N';
  1078.             }
  1079.         }
  1080.         if (yn == 'Y' && flg_m == 0) {
  1081.             fprintf(stderr, "'%s' : %s", name, M_OVERWT);
  1082.             yn = getyn();                /* may overwrite? */
  1083.         }
  1084.         if (yn == 'N') {
  1085.             return FAULT;
  1086.         }
  1087.         setfattr(name, 0x20);            /* reset attributes */
  1088.     }
  1089.     return SUCCS;
  1090. }
  1091.  
  1092. /*******************************
  1093.     read header-ID (method)
  1094. *******************************/
  1095. int tstID(uchar *h)
  1096. {
  1097.     int m;
  1098.     static uchar IDpat[4][6] =
  1099.         {"-lz4-", "-lz5-", "-lh0-", "-lh1-"};
  1100.  
  1101.     m = 3;
  1102.     while (m >= 0 && memcmp(h, IDpat[m], 5)) {
  1103.         m--;
  1104.     }
  1105.     return m;
  1106. }
  1107.  
  1108. /*******************************
  1109.         e, x, p, t command
  1110. *******************************/
  1111. int extract(void)
  1112. {
  1113.     uchar *p, *q;
  1114.     int m;
  1115.     int cnt = 0;
  1116.  
  1117.     openarc1();                            /* open an archive */
  1118.     setvbuf(file1, buf2, _IOFBF, 4096);
  1119.     message("Extract from", arcname);
  1120.     if (flg_v == 1)
  1121.         fprintf(file3, "Extract from '%s'\n", arcname);
  1122.     while ((p = gethdr(file1, &Hdr1)) != NULL) {
  1123.         if (matchpat(filename)) {
  1124.             arcpos0 = ftell(file1) + Hdr1.PacSiz;
  1125.             if (cmd == 'E') {            /* if extract command, */
  1126.                 if (flg_x) {            /* get the destination path name */
  1127.                     p = stpcpy(pathname, basedir);
  1128.                     if (filename[0] == '\\') {
  1129.                         p = pathname;
  1130.                         if (*p && p[1] == ':') {
  1131.                             p += 2;
  1132.                         }
  1133.                     }
  1134.                     stpcpy(p, filename);
  1135.                 } else {
  1136.                     stpcpy(stpcpy(pathname, basedir), p);
  1137.                 }
  1138.             }
  1139.             if (cmd != 'E' || tstdir(pathname)) {
  1140.                 if ((m = tstID(Hdr1.HeadID)) < 0) {
  1141.                     printf("Skipped : '%s' : Unknown method\n", pathname);
  1142.                 } else if (cmd == 'T' && Hdr1.HeadSiz - Hdr1.Fname[0] != 22) {
  1143.                     printf("Skipped : '%s' : CRC not supported\n", filename);
  1144.                 } else {
  1145.                     cnt++;
  1146.                     p = "Melting ";
  1147.                     q = "Melted ";
  1148.                     switch (cmd) {
  1149.                         case 'E':
  1150.                             printf("%s ", pathname);
  1151.                             file3 = fopen(outfname = pathname, "wb");
  1152.                             break;
  1153.                         case 'T':
  1154.                             printf("%s ", filename);
  1155.                             file3 = fopen("nul", "wb");
  1156.                             p = "Testing ";
  1157.                             q = "Tested ";
  1158.                             break;
  1159.                         case 'P':
  1160.                             if (flg_v != 2)
  1161.                                 fprintf(file3, "<<< %s >>>\n", filename);
  1162.                             if (flg_v)
  1163.                                 printf("%s ", filename);
  1164.                             fflush(file3);
  1165.                             setmode(fileno(file3), O_BINARY);
  1166.                             break;
  1167.                     }
  1168.                     if ((ioctl(fileno(file3), 0) & 0x82) == 0x82) {
  1169.                         flg_n = 1;        /* Console output ? */
  1170.                     } else {
  1171.                         setvbuf(file3, buf3, _IOFBF, 4096);
  1172.                     }
  1173.                     blkdisp(Hdr1.OrgSiz, p);
  1174.                     outfile = file3;
  1175.                     infile = file1;
  1176.                     textsize = Hdr1.OrgSiz;
  1177.                     crc = 0;
  1178.                     if (m == 3) {
  1179.                         Decode();        /* extract LHarc's file */
  1180.                     } else if (m == 1) {
  1181.                         DecodeOld();    /* extract LArc's file */
  1182.                     } else {
  1183.                         crcflg = 1;
  1184.                         copyfile(infile, outfile, Hdr1.OrgSiz);
  1185.                         crcflg = 0;        /* only stored file */
  1186.                     }
  1187.                     if (fflush(file3)) {
  1188.                         error(WTERR, outfname);
  1189.                     }
  1190.                     if (cmd == 'E') {
  1191.                         setftime(fileno(file3), &Hdr1.Ftime.s);
  1192.                         fclose(file3);
  1193.                         setfattr(pathname, Hdr1.Attr);
  1194.                         file3 = NULL;
  1195.                     } else if (cmd == 'T') {
  1196.                         fclose(file3);
  1197.                     } else {
  1198.                         setmode(fileno(file3), O_TEXT);
  1199.                         if (flg_v != 2)
  1200.                             fprintf(file3, "\n");
  1201.                     }
  1202.                     curback();
  1203.                     if (Hdr1.HeadSiz - Hdr1.Fname[0] == 22 &&
  1204.                         *(uint *)(&Hdr1.Fname[1] + Hdr1.Fname[0]) != crc) {
  1205.                         errorlevel = 1;                /* test CRC */
  1206.                         printf("CRC err\n");
  1207.                     } else if (cmd != 'P' || flg_v != 0) {
  1208.                         printf("%s\n", q);
  1209.                     }
  1210.                 }
  1211.             }
  1212.             fseek(file1, arcpos0, SEEK_SET);    /* move pointer to next file */
  1213.         } else {
  1214.             fseek(file1, Hdr1.PacSiz, SEEK_CUR);
  1215.         }
  1216.     }
  1217.     fclose(file1);
  1218.     file1 = NULL;
  1219.     return cnt;
  1220. }
  1221.  
  1222. /*******************************
  1223.         d command
  1224. *******************************/
  1225. void delete(void)
  1226. {
  1227.     int cnt = 0;
  1228.  
  1229.     openrwarc1();                        /* open archive */
  1230.     if (patno == 0) {
  1231.         error(NOFNERR, NULL);
  1232.     }
  1233.     message("Updating archive", arcname);
  1234.     openbackup1();                        /* rename to temporary name */
  1235.     openbackup2();                        /* open another temporary file */
  1236.     while (gethdr(file1, &Hdr1)) {
  1237.         if (matchpat(filename)) {
  1238.             message("Deleting", filename);
  1239.             cnt++;
  1240.             fseek(file1, Hdr1.PacSiz, SEEK_CUR);    /* skip file */
  1241.         } else {
  1242.             copyold();
  1243.         }
  1244.     }
  1245.     endofupdate(cnt);                    /* end-of-job process */
  1246. }
  1247.  
  1248. /*******************************
  1249.         s command
  1250. *******************************/
  1251. void self(void)
  1252. {
  1253.     uchar *p, /* *q,*/ buf[12], yn;
  1254.     int flg, i;
  1255.     long l, m, n;
  1256.     void sfx(void), sfx2(void);
  1257.  
  1258.     openarc1();                                /* open archive */
  1259.     message("Making Sfx from archive", arcname);
  1260.     stpcpy(stpcpy(backup2, workdir), "lharc.)2(");
  1261.     file2 = e_fopen(outfname = backup2, "w+b", MKTMPERR);
  1262.                                             /* open temporary */
  1263.     while (gethdr(file1, &Hdr1)) {
  1264.         flg = 0;
  1265.         if (matchpat(filename)) {
  1266.             printf("Extracting '%s' ", filename);
  1267.             if (tstID(Hdr1.HeadID) < 2) {
  1268.                 printf("(not supported) skipped.");
  1269.             } else {
  1270.                 if (flg_x == 0 && (p = j_strrchr(filename, '\\')) != NULL) {
  1271.                     p++;                    /* delete directory part */
  1272.                     Hdr1.Fname[0] = strlen(p);
  1273.                     i = p - filename;
  1274.                     Hdr1.HeadSiz -= i;
  1275.                     memcpy(Hdr1.Fname + 1, Hdr1.Fname + 1 + i,
  1276.                                                 Hdr1.Fname[0] + 2);
  1277.                     Hdr1.HeadChk = mksum(&Hdr1);    /* recalculate sum */
  1278.                 }
  1279.                 wthdr(&Hdr1);
  1280.                 copyfile(file1, file2, Hdr1.PacSiz);
  1281.                 flg = 1;
  1282.             }
  1283.             printf("\n");
  1284.         }
  1285.         if (flg == 0) {
  1286.             fseek(file1, Hdr1.PacSiz, SEEK_CUR);
  1287.         }
  1288.     }
  1289.     fclose(file1);
  1290.     if (putc(0, file2) == EOF)            /* end-mark of archive */
  1291.         error(WTERR, backup2);
  1292.     if ((l = ftell(file2)) <= 1) {
  1293.         goto self9;
  1294.     }
  1295.     if (flg_x == 0) {
  1296.         m = (uchar*)sfx2 - (uchar*)sfx;        /* size of sfx routine */
  1297.     } else {
  1298.         m = (uchar*)usage - (uchar*)sfx2;
  1299.     }
  1300.     n = l + m;                                /* total size of sfx file */
  1301.     rewind(file2);
  1302.     infname = backup2;
  1303.     extfn(arcname, buf);                    /* make the name of sfx */
  1304.     p = stpcpy(pathname, basedir);
  1305.     strcpy(&buf[8], "COM");
  1306.     if (flg_x || n > 0xfe80ul) {
  1307.         strcpy(&buf[8], "EXE");
  1308.     }
  1309.     packfn(p, buf);
  1310.     if ((getfattr(pathname) & 0x8000) == 0) {    /* if the same name exists */
  1311.         fprintf(stderr, "'%s' : %s", pathname, M_OVERWT);
  1312.         yn = getyn();                            /* may overwrite */
  1313.         if (yn == 'N') {
  1314.             goto self9;
  1315.         }
  1316.     }
  1317.     file3 = e_fopen(outfname = pathname, "wb", MKFILEERR);
  1318.     if (buf[8] == 'E') {                        /* if .EXE */
  1319.         if (flg_x) {
  1320.             n = m;
  1321.         }
  1322.         n += 0x20;
  1323.         ExeHdr.page = (n + 511) / 512;
  1324.         ExeHdr.byte = n % 512;
  1325.         ExeHdr.minalloc = (flg_x ? 0x66c0 : 0x2560) / 0x10;
  1326.         if (fwrite(&ExeHdr, 0x20, 1, file3) == 0)
  1327.             error(WTERR, pathname);
  1328.     }
  1329.     movedata(_CS, (flg_x ? (unsigned)sfx2 : (unsigned)sfx),
  1330.              _DS, (unsigned)buf2, m);
  1331.     if (flg_x) {
  1332.         memcpy(buf2 + 0x34, p, strlen(p));                /* large ver. */
  1333.     } else {
  1334.         *((uint *)buf2 + 1) = (l + m + 0x10f) / 0x10;    /* small ver. */
  1335.     }
  1336.     if (fwrite(buf2, m, 1, file3) == 0)        /* write sfx routine */
  1337.         error(WTERR, pathname);
  1338.     if (flg_x) {
  1339.         if (fwrite(keyword, strlen(keyword) + 1, 1, file3) == 0)
  1340.             error(WTERR, pathname);
  1341.     }
  1342.     copyfile(file2, file3, l);                /* write an archive */
  1343.     printf("\nCreated : '%s'\n", pathname);
  1344.     fclose(file3);
  1345. self9:
  1346.     fclose(file2);
  1347.     unlink(backup2);
  1348. }
  1349.  
  1350. /*******************************
  1351.         l, v command
  1352. *******************************/
  1353. void list(void)
  1354. {
  1355.     uint rt;
  1356.     uchar buf[79], *p;
  1357.     static uchar attr[7] = "ohs--a";
  1358.     int i, j, k, Fno;
  1359.     ulong Osize, Psize;
  1360.  
  1361.     Fno = Osize = Psize = 0;
  1362.     openarc1();                                        /* open archive */
  1363.     printf("Listing of archive : '%s'\n\n", arcname);
  1364.     printf("  Name          Original    Packed  Ratio"
  1365.            "   Date     Time   Attr Type  CRC\n");
  1366.     printf("--------------  --------  -------- ------"
  1367.            " -------- -------- ---- ----- ----\n");
  1368.     while ((p = gethdr(file1, &Hdr1)) != NULL) {
  1369.         if (matchpat(filename)) {
  1370.             rt = ratio(Hdr1.PacSiz, Hdr1.OrgSiz);
  1371.             sprintf(buf, "              %10lu%10lu %3d.%1d%% "
  1372.                     "%2d-%02d-%02d %2d:%02d:%02d ---w       %04X\n",
  1373.                     Hdr1.OrgSiz, Hdr1.PacSiz, rt / 10, rt % 10,
  1374.                     (Hdr1.Ftime.s.ft_year + 80) % 100, Hdr1.Ftime.s.ft_month,
  1375.                     Hdr1.Ftime.s.ft_day, Hdr1.Ftime.s.ft_hour,
  1376.                     Hdr1.Ftime.s.ft_min, Hdr1.Ftime.s.ft_tsec * 2,
  1377.                     *(uint *)(&Hdr1.Fname[1] + Hdr1.Fname[0]));
  1378.             memcpy(&buf[65], Hdr1.HeadID, 5);
  1379.             for (i = 0, j = 1; i < 6; i++, j <<= 1) {    /* attributes */
  1380.                 if (Hdr1.Attr & j) {
  1381.                     k = attr[i];
  1382.                     if (i <= 2) {
  1383.                         buf[63 - i] = k;
  1384.                     } else {
  1385.                         buf[60] = k;
  1386.                     }
  1387.                 }
  1388.             }
  1389.             if (Hdr1.HeadSiz - Hdr1.Fname[0] != 22) {
  1390.                 memset(&buf[71], '*', 4);    /* if no CRC suppoted */
  1391.             }
  1392.             if (flg_x) {
  1393.                 printf("%s\n", filename);    /* display in 2 lines */
  1394.             } else {
  1395.                 if (p != filename) {        /* display in one line */
  1396.                     *buf = '+';
  1397.                 }
  1398.                 memcpy(&buf[2], p, strlen(p));
  1399.             }
  1400.             printf(buf);
  1401.             Fno ++;
  1402.             Osize += Hdr1.OrgSiz;
  1403.             Psize += Hdr1.PacSiz;
  1404.         }
  1405.         if (fseek(file1, Hdr1.PacSiz, 1))
  1406.             break;
  1407.     }
  1408.     if (Fno) {
  1409.         printf("--------------  --------  -------- ------"
  1410.                " -------- --------\n");
  1411.         rt = ratio(Psize, Osize);
  1412.         getftime(fileno(file1), &arcstamp.s);
  1413.         printf("   %3d files  %10lu%10lu %3d.%1d%% "
  1414.                "%2d-%02d-%02d %2d:%02d:%02d\n",
  1415.                Fno, Osize, Psize, rt / 10, rt % 10,
  1416.                (arcstamp.s.ft_year + 80) % 100, arcstamp.s.ft_month,
  1417.                arcstamp.s.ft_day, arcstamp.s.ft_hour,
  1418.                arcstamp.s.ft_min, arcstamp.s.ft_tsec * 2);
  1419.     } else {
  1420.         printf("    no file\n");
  1421.     }
  1422.     fclose(file1);
  1423. }
  1424.  
  1425. /*******************************
  1426.         get switches
  1427. *******************************/
  1428. void getsw(uchar *p)
  1429. {
  1430.     static uchar flg[] = "rpxmacntvw";
  1431.     static uchar *flgpos[] = {&flg_r, &flg_p, &flg_x, &flg_m,
  1432.                               &flg_a, &flg_c, &flg_n, &flg_t,
  1433.                               &flg_v, &flg_w};
  1434.     int i;
  1435.     uchar s;
  1436.     uchar *q;
  1437.  
  1438.     while ((s = *p++) != 0) {
  1439.         q = j_strchr(flg, s);        /* search switch */
  1440.         if (q) {
  1441.             i = q - flg;
  1442.             if (*p == '+') {
  1443.                 *flgpos[i] = 1;
  1444.                 p++;
  1445.             } else if (*p == '-') {
  1446.                 *flgpos[i] = 0;
  1447.                 p++;
  1448.             } else if (*p == '2') {
  1449.                 *flgpos[i] = 2;
  1450.                 p++;
  1451.             } else if (s == 'v' && *p) {
  1452.                 if (flg_v == 0)            /* process of '/vSTRING' */
  1453.                     flg_v = 1;
  1454.                 pager = p;
  1455.                 p = "";
  1456.             } else if (s == 'w' && *p) {
  1457.                 flg_w = 1;                /* process of '/wSTRING' */
  1458.                 wdir = p;
  1459.                 p = "";
  1460.             } else {
  1461.                 if (*flgpos[i]) {        /* flip-flop */
  1462.                     *flgpos[i] = 0;
  1463.                 } else {
  1464.                     *flgpos[i] = 1;
  1465.                 }
  1466.             }
  1467.             if (s == 'r' && flg_r > 0) {
  1468.                 flg_x = 1;
  1469.             }
  1470.         } else if (s == 'k') {
  1471.             keyword = p;
  1472.             p = "";
  1473.         } else {
  1474.             if (s == '?') usage();
  1475.             error(INVSWERR, NULL);
  1476.         }
  1477.     }
  1478. }
  1479.  
  1480. /*******************************
  1481.         execute command
  1482. *******************************/
  1483. void executecmd()
  1484. {
  1485.     int handle;
  1486.     int cnt;
  1487.  
  1488.     switch (cmd) {
  1489.     case 'A':
  1490.         flg_c++;
  1491.     case 'U':
  1492.     case 'M':
  1493.         append();
  1494.         break;
  1495.     case 'F':
  1496.         freshen();
  1497.         break;
  1498.     case 'P':
  1499.         if (flg_v == 0) {
  1500.            file3 = stdout;
  1501.            goto common;
  1502.         }
  1503.         stpcpy(stpcpy(pathname, workdir), "LHARC.TMP");    /* view files */
  1504.         file3 = e_fopen(outfname = pathname, "w", MKTMPERR);
  1505.         cnt = extract();
  1506.         fclose(file3);
  1507.         if (cnt)                        /* if any files extracted */
  1508.             stpcpy(stpcpy(stpcpy(buf2, pager), " "), pathname);
  1509.             execute(buf2);                /* execute by INT 0x2e */
  1510. #if 0
  1511.             spawnlp(P_WAIT, pager, pager, pathname, NULL);
  1512. #endif
  1513.         unlink(pathname);
  1514.         break;
  1515.     case 'T':
  1516.         tstflg = 1;
  1517.         goto common;
  1518.     case 'X':
  1519.     case 'E':
  1520.         cmd = 'E';
  1521. common:
  1522.         flg_v = 0;
  1523.         extract();
  1524.         break;
  1525.     case 'V':
  1526.         flg_x++;
  1527.     case 'L':
  1528.         list();
  1529.         break;
  1530.     case 'D':
  1531.         delete();
  1532.         break;
  1533.     case 'S':
  1534.         self();
  1535.         break;
  1536.     }
  1537.     fputc('\n', stderr);
  1538. }
  1539.  
  1540. int cbrk;
  1541.  
  1542. void recovercbrk(void) {
  1543.     setcbrk(cbrk);
  1544. }
  1545.  
  1546. /*******************************
  1547.         main routine
  1548. *******************************/
  1549. int main(int argc, uchar *argv[])
  1550. {
  1551.     uchar *p, *q, *env, *env9;
  1552.     int i, yn;
  1553.     extern char title[];
  1554.     struct ffblk ffb;
  1555.  
  1556.     ctrlbrk(userbreak);                    /* set vector for '^C' */
  1557.     cbrk = getcbrk();
  1558.     setcbrk(1);
  1559.     atexit(recovercbrk);
  1560.     fputs(title, stderr);                /* output title */
  1561.     putchar('\n');
  1562.     mkcrc();                            /* make CRC table */
  1563.     swchar = getswchar();                /* get the setting of switch char */
  1564.     argc--;
  1565.     argv++;
  1566.     if (argc-- == 0)
  1567.         usage();                        /* if no parameter given */
  1568.     p = (argv++)[0];
  1569.     cmd = toupper(*p);
  1570.     if (strlen(p) - 1 || j_strchr("EXTDLVAUMFPS", cmd) == 0) {
  1571.         cmd = 'L';                        /* if no command, assume 'L' command */
  1572.         argc++;
  1573.         argv--;
  1574.     }
  1575.     cmdupdate = (int)j_strchr("AUMFD", cmd);    /* command updating archive? */
  1576.     if ((env = getenv("TMP")) != NULL) {    /* get 'TMP' from environment */
  1577.         wdir = env;
  1578.         flg_w = 1;
  1579.     }
  1580.     if ((env = getenv("LHARC")) != NULL) {    /* get 'LHARC' from environment */
  1581.         for (p = env; *p != '\0'; p++) {
  1582.             if (*p == ' ' || *p == '\x08')
  1583.                 *p = '\0';
  1584.         }
  1585.         env9 = p;
  1586.         p = env;
  1587.         while (p < env9) {
  1588.             while (*p == '\0') p++;
  1589.             if (*p == swchar || *p == '-') p++;
  1590.             getsw(p);
  1591.             while (*p) p++;
  1592.         }
  1593.     }
  1594.     patno = -1;
  1595.     basedir = NULL;
  1596.     while (argc--) {
  1597.         p = (argv++)[0];
  1598.         if (*p == swchar || *p == '-') {
  1599.             getsw(++p);
  1600.         } else {
  1601.             slash2yen(j_strupr(p));        /* convert '/' to '\' */
  1602.             if (patno < 0) {            /* get archive name */
  1603.                 strcpy(arcname, p);
  1604.                 if ((p = j_strrchr(arcname, '\\')) == NULL) {
  1605.                     p = arcname;        /* pointer of the part of file name */
  1606.                 }
  1607.                 if ((q = j_strchr(p, '.')) == NULL) {
  1608.                     strcat(arcname, ".LZH");    /* if no extension */
  1609.                 } else if (j_strcmp(".LZH", q) && flg_m == 0 && cmdupdate) {
  1610.                     fprintf(stderr, M_NOTLZH, arcname);
  1611.                     yn = getyn();        /* if the extension is not '.LZH' */
  1612.                     if (yn == 'N') {
  1613.                         exit(1);
  1614.                     }
  1615.                 }
  1616.                 patno++;
  1617.             } else {
  1618.                 if (patno == 0 && basedir == NULL &&
  1619.                     (j_strrchr(p, '\\') == p + strlen(p) - 1 ||
  1620.                      p[strlen(p) - 1] == ':')) {
  1621.                     basedir = p;    /* get base (or home) directory */
  1622.                 } else if (patno >= MAX_PAT) {
  1623.                     message("File table overflow. ignore", p);
  1624.                 } else {
  1625.                     patpath[patno] = p;
  1626.                     extfn(p, patfile[patno]);
  1627.                     patno++;        /* regist path names */
  1628.                 }
  1629.             }
  1630.         }
  1631.     }
  1632.     if (patno < 0) {
  1633.         error(NOARCNMERR, NULL);
  1634.     }
  1635.     if (patno == 0 && cmd != 'D') {                /* if no name given */
  1636.         extfn(patpath[0] = patnul, patfile[0]);    /* '*.*' is assumed */
  1637.         patno++;
  1638.     }
  1639.     p = stpcpy(workdir, wdir) - 1;
  1640.     if (*workdir != '\0' && j_strrchr(workdir, '\\') != p && *p != ':') {
  1641.         strcat(workdir, "\\");        /* concatenate '\' after the work dir. */
  1642.     }
  1643.     if (cmdupdate) {
  1644.         if (j_strchr(arcname, '*') || j_strchr(arcname, '?')) {
  1645.             error(NOARCERR, arcname);
  1646.         }                    /* when updating archive, wild cards can't used */
  1647.         executecmd();
  1648.     } else {
  1649.         if (findfirst(arcname, &ffb, 0x07)) {
  1650.             error(NOARCERR, arcname);
  1651.         }
  1652.         do {
  1653.             strcpy(backpath(arcname), ffb.ff_name);
  1654.             executecmd();
  1655.         } while (!findnext(&ffb));
  1656.         if (cmd != 'L' && cmd != 'V')
  1657.             tstpat();                /* whether all given names were used? */
  1658.     }
  1659.     return errorlevel;
  1660. }
  1661.